﻿namespace AddressBook.Business.Event
{
	#region "Using Statements"
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;

	using Csla;
	using Csla.Data;
	using Csla.Validation;

	using Business.Contact;
	using Business.Person;
	#endregion

	public interface IMailingAddress
	{
		String Name { get; }
		IAddress Address { get; }
	}

	public enum GuestType
	{
		Contact = 1,
		Family = 2,
	}

	[Serializable]
	public class Guest : BusinessBase<Guest>, IMailingAddress
	{
		#region "Business Methods"

		#region "Private Static Member Variables"

		private static PropertyInfo<Int32> EventIdProperty = RegisterProperty<Int32>(g => g.EventId);
		private static PropertyInfo<Int32> GuestIdProperty = RegisterProperty<Int32>(g => g.GuestId);
		private static PropertyInfo<GuestType> GuestTypeIdProperty = RegisterProperty<GuestType>(g => g.GuestType);
		private static PropertyInfo<String> NameProperty = RegisterProperty<String>(g => g.Name);
		private static PropertyInfo<IAddress> AddressProperty = RegisterProperty<IAddress>(g => g.Address);
		private static PropertyInfo<SmartDate> ModifiedDateProperty = RegisterProperty<SmartDate>(g => g.ModifiedDate);

		#endregion

		#region "Public Properties"

		public Int32 EventId
		{
			get { return GetProperty(EventIdProperty); }

			internal set { LoadProperty(EventIdProperty, value); }
		}

		public Int32 GuestId
		{
			get { return GetProperty(GuestIdProperty); }

			internal set { LoadProperty(GuestIdProperty, value); }
		}

		public GuestType GuestType
		{
			get { return GetProperty(GuestTypeIdProperty); }

			internal set { LoadProperty(GuestTypeIdProperty, value); }
		}

		public String ModifiedDate
		{
			get { return GetProperty(ModifiedDateProperty).ToString(); }
		}

		public String Name
		{
			get { return GetProperty(NameProperty); }

			internal set { LoadProperty(NameProperty, value); }
		}

		public IAddress Address
		{
			get { return GetProperty(AddressProperty); }

			internal set { LoadProperty(AddressProperty, value); }
		}

		#endregion

		#endregion

		#region "Business Rules"



		#endregion

		#region "Factory Methods"

		public static Guest NewGuest()
		{
			return DataPortal.CreateChild<Guest>();
		}

		public static Guest NewGuest(Int32 guestId, GuestType guestType)
		{
			return DataPortal.CreateChild<Guest>(new GuestCriteria(guestId, guestType));
		}

		public static Guest GetGuest(AddressBook.Business.Model.Guest data)
		{
			return DataPortal.FetchChild<Guest>(data);
		}

		#endregion

		#region "Data Access"

		#region "Internal GuestCriteria Class"
		internal class GuestCriteria
		{
			public Int32 GuestId;
			public GuestType GuestType;

			public GuestCriteria(Int32 guestId, GuestType guestType)
			{
				this.GuestId = guestId;
				this.GuestType = guestType;
			}
		}
		#endregion

		protected override void Child_Create()
		{

		}

		private void Child_Create(GuestCriteria criteria)
		{
			using (BypassPropertyChecks)
			{
				this.GuestId = criteria.GuestId;
				this.GuestType = criteria.GuestType;

				using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
				{
					switch (this.GuestType)
					{
						case GuestType.Contact:
							Contact contact = Contact.GetContact(this.GuestId);
							LoadProperty(NameProperty, Business.Person.Contact.GetFullName(contact.FirstName, contact.MiddleName, contact.LastName, contact.Suffix));
							LoadProperty(AddressProperty, contact.Addresses.FirstOrDefault(ca => ca.AddressTypeId == 1));
							break;

						case GuestType.Family:
							Family family = Family.GetFamily(this.GuestId);
							LoadProperty(NameProperty, family.Name);
							LoadProperty(AddressProperty, family.Address);
							break;
					}
				}
			}
		}

		private void Child_Fetch(AddressBook.Business.Model.Guest data)
		{
			using (BypassPropertyChecks)
			{
				this.EventId = data.EventId;
				this.GuestId = data.GuestId;
				this.GuestType = (GuestType)data.GuestTypeId;

				LoadProperty(ModifiedDateProperty, data.ModifiedDate);

				using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
				{
					switch (this.GuestType)
					{
						case GuestType.Contact:
							Contact contact = Contact.GetContact(this.GuestId);
							LoadProperty(NameProperty, Business.Person.Contact.GetFullName(contact.FirstName, contact.MiddleName, contact.LastName, contact.Suffix));
							LoadProperty(AddressProperty, contact.Addresses.FirstOrDefault(ca => ca.AddressTypeId == 1));
							break;

						case GuestType.Family:
							Family family = Family.GetFamily(this.GuestId);
							LoadProperty(NameProperty, family.Name);
							LoadProperty(AddressProperty, family.Address);
							break;
					}
				}
			}
		}

		private void Child_Insert(Event parent)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// insert guest data
				using (BypassPropertyChecks)
				{
					AddressBook.Business.Model.Guest guest = new AddressBook.Business.Model.Guest();

					guest.EventId = parent.Id;
					guest.GuestId = this.GuestId;
					guest.GuestTypeId = (int)this.GuestType;
					guest.ModifiedDate = System.DateTime.Now;

					ctx.DataContext.Guests.InsertOnSubmit(guest);
					ctx.DataContext.SubmitChanges();
				}
			}
		}

		private void Child_Update()
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				// update guest data
				using (BypassPropertyChecks)
				{
					AddressBook.Business.Model.Guest guest = ctx.DataContext.Guests.First(g => g.EventId == this.EventId && 
																																					 g.GuestId == this.GuestId && 
																																					 g.GuestTypeId == (int)this.GuestType);

					guest.EventId = this.EventId;
					guest.GuestId = this.GuestId;
					guest.GuestTypeId = (int)this.GuestType;

					guest.ModifiedDate = System.DateTime.Now;

					ctx.DataContext.SubmitChanges();
				}
			}
		}

		private void Child_DeleteSelf(Event parent)
		{
			using (var ctx = ContextManager<AddressBook.Business.Model.AddressBookDataContext>.GetManager(AddressBook.Business.Model.Database.AddressBook))
			{
				AddressBook.Business.Model.Guest guest = ctx.DataContext.Guests.First(g => g.EventId == parent.Id && 
																																				 g.GuestId == this.GuestId && 
																																				 g.GuestTypeId == (int)this.GuestType);

				ctx.DataContext.Guests.DeleteOnSubmit(guest);
				ctx.DataContext.SubmitChanges();
			}
		}

		#endregion
	}
}
